package stc.skymobi.bsh.cmds;

import bsh.CallStack;
import bsh.Interpreter;
import com.alibaba.fastjson.JSON;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.List;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.jocean.util.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class callmbean {
	private static final Logger LOG = LoggerFactory.getLogger(callmbean.class);

	public static void invoke(Interpreter env, CallStack callstack,
			String objname, String methodName, String[] methodParams)
			throws Exception {
		MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
		ObjectName on = ObjectName.getInstance(objname);
		int methodParamsCount = methodParams != null ? methodParams.length : 0;
		if (LOG.isDebugEnabled()) {
			LOG.debug("try to invoke {}.{} with {} params", new Object[] {
					objname, methodName, Integer.valueOf(methodParamsCount) });
		}
		MBeanOperationInfo opInfo = getOperationInfo(mbs, on, methodName,
				methodParamsCount);
		if (opInfo != null) {
			try {
				List<Object> paramList = new ArrayList();
				List<String> signatureList = new ArrayList();
				MBeanParameterInfo[] paramInfos = opInfo.getSignature();
				for (int idx = 0; idx < paramInfos.length; idx++) {
					MBeanParameterInfo paramInfo = paramInfos[idx];

					paramList.add(JSON.parseObject(methodParams[idx],
							Class.forName(paramInfo.getType())));
					signatureList.add(paramInfo.getType());
				}
				Object retVal = mbs.invoke(on, methodName,
						paramList.toArray(new Object[0]),
						(String[]) signatureList.toArray(new String[0]));
				env.eval("print(\"invoke " + objname + "." + methodName
						+ " return value("
						+ (retVal != null ? retVal.toString() : "null")
						+ ")\");");
			} catch (Exception e) {
				LOG.error(
						"exception when invoke {}.{}, detail: {}",
						new Object[] { objname, methodName,
								ExceptionUtils.exception2detail(e) });
			}
		} else {
			LOG.warn(
					"can't found {}.{} with {} params, invoke failed.",
					new Object[] { objname, methodName,
							Integer.valueOf(methodParamsCount) });
			env.eval("print(\"" + objname + "." + methodName
					+ " not found!\");");
		}
	}

	private static MBeanOperationInfo getOperationInfo(MBeanServer mbs,
			ObjectName on, String methodName, int paramCount) throws Exception {
		MBeanInfo info = mbs.getMBeanInfo(on);
		MBeanOperationInfo[] ops = info.getOperations();
		for (MBeanOperationInfo op : ops) {
			if ((op.getName().equals(methodName))
					&& (op.getSignature().length == paramCount)) {
				return op;
			}
		}
		return null;
	}
}
